package com.totoro.redis.cookie;

import com.google.common.collect.Sets;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.util.List;
import java.util.Set;

/**
 * Created by Administrator on 2017/11/13/013.
 */
@Service
public class TokenCookieUtil {
    @Resource
    RedisTemplate redisTemplate;
    @Resource
    StringRedisTemplate stringRedisTemplate ;


    /**
     * 保存缓存
     * @param token
     * @param userId
     */
    public void addToken(String token, String userId){
        redisTemplate.opsForHash().put("login:", token, userId);
    }

    /**
     * 存储cookie令牌与已登录用户之间的映射，如果用户已经登录，则返回用户id
     *
     * @param token
     * @return
     */
    public String checkToken(String token) {
        String userId = (String) redisTemplate.opsForHash().get("login:", token);
        return userId;
    }

    /**
     * 用户浏览页面时更新用户的token， 并且记录下用户浏览的商品集合，并且只记录25条，超过的25条删除
     * @param token
     * @param userId
     * @param items
     */
    public void updateToken(String token, String userId, List<String> items) {
        Instant timestamp = Instant.now();
        //保存用户登录
        redisTemplate.opsForHash().put("login", token, userId);
        //记录令牌最后一次出现时间
        redisTemplate.opsForZSet().add("recent:", token, timestamp.getNano());

        for (String item : items){
            //记录用户浏览的商品
            redisTemplate.opsForZSet().add("viewed:"+token, item, timestamp.getNano());
            //记录用户最近浏览的25个商品，超过的删除
            redisTemplate.opsForZSet().removeRangeByScore("viewed:"+token, 0, -26) ;
        }
    }

    /**
     * 保存最新的1000000个会话，超过部分清楚 ，每隔一秒钟运行一次检查
     */
    private static long LIMIT = 1000000 ;
    public void cleanSession() throws InterruptedException {
        long size = redisTemplate.opsForZSet().zCard("recent:") ;
        if(size <= LIMIT){
            Thread.sleep(1000);
        }

        //获取需要移除的令牌下表
        long end_index =  Math.min(size-LIMIT, 100) ;
        //需要移除的令牌id
        Set<String> tokens = redisTemplate.opsForZSet().range("recent",0, end_index) ;

        Set<String> session_keys = Sets.newHashSet() ;
        for(String token : tokens){
            session_keys.add("viewed:"+token) ;
        }

        //移除token与user映射
        stringRedisTemplate.delete(session_keys);
        //移除登录的令牌
        redisTemplate.opsForHash().delete("login:", tokens) ;
        //移除最近浏览商品
        redisTemplate.opsForZSet().remove("recent:", tokens) ;

    }

    public static void main(String[] args) {
        System.out.println(Instant.now().getNano());
    }
}
